#pragma once

#include <metalc/meta/_meta.h>
#include <dinfra/flatmap.h>

#define PGBYTE_IS_HEAD		(0) // 普通的CHK
#define PGBYTE_IS_PART		(1)

#define PGBYTE_UNKNOWN		(0)
#define PGBYTE_CHK_SMALL	(1)
#define PGBYTE_CHK_FREE		(2) // free的
#define PGBYTE_CHK_BIG		(3)  // BIG IN USED

#define PGBYTE_STATE(n)		(n << 1UL)
#define PGBYTE_ORDER(n)		(n << 3UL)



typedef union
{
	byte_t __c;
	struct
	{
		byte_t head_bit	: 1;
		byte_t state	: 2;
		byte_t add_ord	: 5;
	};
} pgbyte_t;

typedef byte_t pgmap_t;

// #define PAGE_BITS   (48)
// #define PAGE_SIZE   (4096)
#define DEF_PGMAP(PGMAP_PTR_BITS, PGMAP_PAGESHIFT, get_pages, ret_pages)			\
DEF_FLATMAP(byte, pgbyte, 1UL << (PGMAP_PTR_BITS - PGMAP_PAGESHIFT), get_pages, ret_pages)	\
static inline pgmap_t *pgmap_create(){ return flatmap_create_pgbyte();  }			\
SAI size_t pgmap_chksize(){ return 1UL << PGMAP_PAGESHIFT; }					\
SAI word_t pgbyte_get_chksize(pgbyte_t byte)							\
{\
	/* assert(byte.state != PGBYTE_UNKNOWN);		\
		assert(byte.head_bit == PGBYTE_IS_HEAD);*/  \
	if (byte.state == PGBYTE_CHK_BIG)			\
		return pgmap_chksize() << byte.add_ord;			\
	else											\
		return pgmap_chksize();\
}\
SAI byte_t pgmap_get(pgmap_t *p, void *ptr)\
{\
	return flatmap_get_pgbyte(p, ((word_t)ptr) >> PGMAP_PAGESHIFT)\
}\
SAI word_t __fp_pgmap_findhdidx(pgmap_t *p, word_t idx)\
{\
	pgbyte_t val;\
	word_t next_idx;\
	val.__c = flatmap_get_pgbyte(p, idx);\
	if (val.head_bit == PGBYTE_IS_HEAD)\
		return idx;\
	next_idx = idx - (1UL << val.add_ord);\
	return __fp_pgmap_findhdidx(p, next_idx);\
}\
SAI word_t pgmap_get_chksize(pgmap_t *p, void *ptr)\
{\
	word_t idx = ((word_t)ptr) >> PGMAP_PAGESHIFT;\
	word_t hdidx = __fp_pgmap_findhdidx(p, idx);\
	pgbyte_t hdval;\
	hdval.__c = flatmap_get_pgbyte(p, idx);\
	if (hdval.__c == 0) return 0;		\
	return pgbyte_get_chksize(hdval);\
}\
SAI word_t pgmap_get_chksize_ishdr(pgmap_t *p, void *ptr, bool_t *is_head)\
{\
	word_t idx = ((word_t)ptr) >> PGMAP_PAGESHIFT;\
	word_t hdidx = __fp_pgmap_findhdidx(p, idx);\
	pgbyte_t hdval;\
	*is_head = (ptr == (void *)(hdidx << PGMAP_PAGESHIFT)) ? 1 : 0;\
	hdval.__c = flatmap_get_pgbyte(p, hdidx);\
	return pgbyte_get_chksize(hdval);\
}\
SAI void *pgmap_get_chkhd(pgmap_t *p, void *ptr)\
{\
	word_t idx = ((word_t)ptr) >> PGMAP_PAGESHIFT;\
	word_t hdidx = __fp_pgmap_findhdidx(p, idx);\
	return (void *)(hdidx << PGMAP_PAGESHIFT);\
}/* 这个下面应该是给buddy用的 */\
SAI void __pgmap_set_chk(pgmap_t *p, void *chk_ptr, word_t nr, pgbyte_t flag)\
{\
	word_t sidx = ((word_t)chk_ptr) >> PGMAP_PAGESHIFT;\
	/* p->flt[sidx] = flag.__c | PGBYTE_IS_HEAD | PGBYTE_ORDER(LOG2_ALIGN(size >> PGMAP_PAGESHIFT)); // BIG */\
	flatmap_set_pgbyte(sidx, flag.__c | PGBYTE_IS_HEAD | PGBYTE_ORDER(LOG2_ALIGN(nr)));\
	word_t j = 1; word_t order = 0; \
	for (word_t i = 1; i < nr; i++)\
	{\
		/*p->flt[i] = flag.__c | PGBYTE_IS_PART | PGBYTE_ORDER(order); //JMP*/\
		flatmap_set_pgbyte(sidx+i, flag.__c | PGBYTE_IS_PART | PGBYTE_ORDER(order));\
		j++;\
		if (is_powerof2(j)){ order += 1; }								\
	}\
}\
SAI void pgmap_set_chk(pgmap_t *p, void *chk_ptr, word_t size)\
{\
	pgbyte_t flag;\
	flag.__c = 0;\
	if (size > pgmap_chksize())\
		flag.state = PGBYTE_CHK_BIG;\
	else\
		flag.state = PGBYTE_CHK_SMALL;\
	__pgmap_set_chk(p, chk_ptr, size >> PAGE_SHIFT, flag);\
}\
SAI void pgmap_clear_chk(pgmap_t *p, void *chk_ptr, word_t size)\
{\
	pgbyte_t flag;\
	flag.__c = 0;\
	word_t sidx = ((word_t)chk_ptr) >> PGMAP_PAGESHIFT;\
	word_t nr = size >> PGMAP_PAGESHIFT;						\
	for (word_t i = 0; i < nr; i++)\
	{\
		flatmap_set_pgbyte(sidx + i, flag.__c);\
	}\
}


/* 如果刚好找到，说明该页被分配 */
/* 如果没找到，说明该页没有被分配 */

/* 仅适用于 2分系统 */
// #define DEF_PGMAP_MMETA(name, PGMAP_PTR_BITS, PGMAP_PAGESHIFT, get_pages, ret_pages)\
// DECL_GETMETASIZE(name)\
// DEF_PGMAP()
